package com.example.connecting_dots_android;

import interfaces.IHandler;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import model.Directions;
import model.GameHandler;
import model.Line;
import model.Player;
import model.ResultItem;
import model.ScoreComparator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class StartGame extends Activity {
	private static final int BOARD_SIZE = 4;

	public IHandler mGameHandler;
	public Player mPlayerOne;
	private Player mPlayerTwo;
	private int mTurns = -1;
	private int mRow;
	private int mCol;
	private Directions mDirection;
	public Map<String, Integer> mSigns;
	private TextView mFirstPlayerTextView;
	private TextView mSecondPlayerTextView;
	private List<Integer> mLineButtontsNotDrownYet;
	private boolean mIsMute = false;
	private Player mCurrentPlayer;
	public Map<Integer, Integer> mSignsIDs = new HashMap<Integer, Integer>();

	public OnClickListener mShowListener = new OnClickListener() {

		@Override
		public void onClick(View view) {
			makeAMove((Button) view, mPlayerOne);
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_game);
		init();
		settings();
		initSignsIDs();
	}

	/**
	 * method to manage background image and music
	 * */
	private void settings() {
		Utils.setBackgroundImage(this, findViewById(R.id.activity_game));

		if (MainActivity.mServ != null && mIsMute
				&& !MainActivity.mServ.isPlaying()) {
			MainActivity.mServ.resume();
		}

		// Show the Up button in the action bar.
		setupActionBar();
	}

	/**
	 * method to initialize class members
	 * 
	 * */
	private void init() {
		mIsMute = Utils.getIsMute(this);
		mFirstPlayerTextView = (TextView) findViewById(R.id.idNameFirstPlayerLabel);
		mSecondPlayerTextView = (TextView) findViewById(R.id.idNameSecondPlayerLabel);

		Bundle extras = getIntent().getExtras();
		if (extras != null) {
			mPlayerOne = new Player(extras.getString("playerOneName"),
					Constants.PLAYER_X);
			mPlayerTwo = new Player(extras.getString("playerTwoName"),
					Constants.PLAYER_O);
		}

		mFirstPlayerTextView.setText(mPlayerOne.getName() + ": 0");
		mSecondPlayerTextView.setText(mPlayerTwo.getName() + ": 0");
		mFirstPlayerTextView.setTextColor(Color.CYAN);

		mSigns = new HashMap<String, Integer>();
		mSigns.put("firstPlayerSign", R.drawable.player_one_sign);
		mSigns.put("secondPlayerSign", R.drawable.player_two_sign);

		mGameHandler = new GameHandler(BOARD_SIZE);

		mLineButtontsNotDrownYet = new ArrayList<Integer>();

		clickButton();
		lineButtons();
	}

	/**
	 * Set up the {@link android.app.ActionBar}, if the API is available.
	 */
	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	private void setupActionBar() {
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
			getActionBar().setDisplayHomeAsUpEnabled(true);
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.start_game, menu);
		return true;
	}

	/**
	 * method to simulate computer move
	 * */
	private boolean computerTurn() {
		Random rand = new Random();

		Button button = (Button) findViewById(mLineButtontsNotDrownYet.get(rand
				.nextInt(mLineButtontsNotDrownYet.size())));
		boolean scored = makeAMove(button, mPlayerTwo);

		return scored;
	}

	/**
	 * method to save the move made
	 * */
	private boolean makeAMove(Button button, Player player) {
		mLineButtontsNotDrownYet.remove((Integer) button.getId());

		button.setClickable(false);
		button.setVisibility(View.VISIBLE);

		if (mPlayerTwo.getName().equals(Constants.COMPUTER_PLAYER)) {
			mCurrentPlayer = player;
		} else {
			mCurrentPlayer = playerOnTurn();
		}

		changePlayerColor();

		boolean scored = false;
		int emptyCellsInStartOfTurn = mGameHandler.getEmptyCellsCount();

		setLineCoordinates(button);
		Line line = new Line(mRow, mCol, mDirection);
		scored = mGameHandler.updateGameBoard(line, mCurrentPlayer.getSign());

		if (line.getDirection() == Directions.R) {
			button.setBackgroundResource(R.drawable.line_shape_button);
		} else {
			button.setBackgroundResource(R.drawable.line_shape_button_vertical);
		}

		if (scored) {
			int numberOfPointsScored = emptyCellsInStartOfTurn
					- mGameHandler.getEmptyCellsCount();

			increasePlayerScore(mCurrentPlayer, numberOfPointsScored);

			putSignOnTheRighPlace(mCurrentPlayer, line, numberOfPointsScored);

			mTurns++;
		}

		if (isOver()) {
			scored = false;
			if (mCurrentPlayer.getName().equals(mPlayerTwo.getName())) {
				restartGame();
			} else if (!mPlayerTwo.getName().equals(Constants.COMPUTER_PLAYER)) {
				restartGame();
			}
		}

		if (mCurrentPlayer.getName().equals(mPlayerOne.getName())) {
			if (mPlayerTwo.getName().equals(Constants.COMPUTER_PLAYER)) {
				if (!isOver()) {
					if (!scored) {
						while (computerTurn()) {
						}
					}
				} else {
					restartGame();
				}
			}
		}

		return scored;
	}

	/**
	 * method to set OnCLickListeners to the board's line buttons
	 * */
	public void clickButton() {
		for (int i = 0; i < Constants.gameButtons.length; i++) {
			((Button) findViewById(Constants.gameButtons[i]))
					.setOnClickListener(mShowListener);
			;
		}
	}

	/**
	 * method to mark finished square
	 * */
	public void putSignOnTheRighPlace(Player player, Line line,
			int numberOfPointsScored) {

		ImageView setSign = getImageViewToWritePLayerSign(
				mGameHandler.getLastFilledSignCellRow(),
				mGameHandler.getLastFilledSignCellCol());

		setImageForPlayer(player, setSign);

		if (numberOfPointsScored == 2) {

			ImageView setSign2;

			if (line.getDirection() == Directions.R) {
				setSign2 = getImageViewToWritePLayerSign(
						(mGameHandler.getLastFilledSignCellRow() - 2),
						mGameHandler.getLastFilledSignCellCol());
			} else {
				setSign2 = getImageViewToWritePLayerSign(
						mGameHandler.getLastFilledSignCellRow(),
						mGameHandler.getLastFilledSignCellCol() - 2);
			}

			setImageForPlayer(player, setSign2);
		}
	}

	/**
	 * method to pick up right player's sign
	 * */
	private void setImageForPlayer(Player player, ImageView setSign) {
		if (player.equals(mPlayerOne)) {
			setSign.setImageResource(mSigns.get("firstPlayerSign"));
		} else {
			setSign.setImageResource(mSigns.get("secondPlayerSign"));
		}
	}

	/**
	 * method to get row, column and direction of the picked line
	 * */
	private void setLineCoordinates(View view) {
		mRow = setRow((Button) view);
		mCol = setCol((Button) view);
		mDirection = getDirection((Button) view);
	}

	/**
	 * method to increase player's score when score made
	 * */
	private void increasePlayerScore(Player currentPlayer,
			int numberOfPointsScored) {
		if (currentPlayer != null && currentPlayer.equals(mPlayerOne)) {

			mPlayerOne.increaseScore(numberOfPointsScored);
			((TextView) findViewById(R.id.idNameFirstPlayerLabel)).setText(""
					+ mPlayerOne.getName() + ": "
					+ mPlayerOne.getCurrentScore());
			((TextView) findViewById(R.id.idNameFirstPlayerLabel))
					.setTextColor(Color.CYAN);
			((TextView) findViewById(R.id.idNameSecondPlayerLabel))
					.setTextColor(Color.WHITE);

		} else {
			mPlayerTwo.increaseScore(numberOfPointsScored);
			((TextView) findViewById(R.id.idNameSecondPlayerLabel)).setText(""
					+ mPlayerTwo.getName() + ": "
					+ mPlayerTwo.getCurrentScore());
			((TextView) findViewById(R.id.idNameFirstPlayerLabel))
					.setTextColor(Color.WHITE);
			((TextView) findViewById(R.id.idNameSecondPlayerLabel))
					.setTextColor(Color.CYAN);

		}
	}

	/**
	 * method to color current player's name
	 * */
	private void changePlayerColor() {

		if (mCurrentPlayer.equals(mPlayerOne)) {
			((TextView) findViewById(R.id.idNameFirstPlayerLabel))
					.setTextColor(Color.WHITE);
			((TextView) findViewById(R.id.idNameSecondPlayerLabel))
					.setTextColor(Color.CYAN);
		} else {
			((TextView) findViewById(R.id.idNameFirstPlayerLabel))
					.setTextColor(Color.CYAN);
			((TextView) findViewById(R.id.idNameSecondPlayerLabel))
					.setTextColor(Color.WHITE);
		}
	}

	/**
	 * method to get current player
	 * */
	private Player playerOnTurn() {

		this.mTurns++;
		if (mTurns % 2 == 0) {
			return mPlayerOne;
		} else {
			return mPlayerTwo;
		}

	}

	/**
	 * method to return winner's name
	 * */
	private String getWinnerName() {
		if (mPlayerOne.getCurrentScore() > mPlayerTwo.getCurrentScore()) {
			return mPlayerOne.getName();
		} else if (mPlayerTwo.getCurrentScore() > mPlayerOne.getCurrentScore()) {
			return mPlayerTwo.getName();
		} else {
			return "Equal result";
		}
	}

	/**
	 * method to return winner's score
	 * */
	private int getWinnerScore() {
		if (mPlayerOne.getCurrentScore() > mPlayerTwo.getCurrentScore()) {
			return mPlayerOne.getCurrentScore();
		} else {
			return mPlayerTwo.getCurrentScore();
		}
	}

	/**
	 * method to get line direction according to the clicked line
	 * */
	public Directions getDirection(Button btn) {
		int btnID = btn.getId();

		switch (btnID) {
		case R.id.btn02:
		case R.id.btn04:
		case R.id.btn06:
		case R.id.btn08:
		case R.id.btn22:
		case R.id.btn24:
		case R.id.btn26:
		case R.id.btn28:
		case R.id.btn42:
		case R.id.btn44:
		case R.id.btn46:
		case R.id.btn48:
		case R.id.btn62:
		case R.id.btn64:
		case R.id.btn66:
		case R.id.btn68:
		case R.id.btn82:
		case R.id.btn84:
		case R.id.btn86:
		case R.id.btn88:

			return Directions.R;

		case R.id.btn11:
		case R.id.btn13:
		case R.id.btn15:
		case R.id.btn17:
		case R.id.btn19:
		case R.id.btn31:
		case R.id.btn33:
		case R.id.btn35:
		case R.id.btn37:
		case R.id.btn39:
		case R.id.btn51:
		case R.id.btn53:
		case R.id.btn55:
		case R.id.btn57:
		case R.id.btn59:
		case R.id.btn71:
		case R.id.btn73:
		case R.id.btn75:
		case R.id.btn77:
		case R.id.btn79:

			return Directions.D;
		}
		return null;
	}

	/**
	 * method to get the row of the clicked line
	 * */
	public int setRow(Button btn) {
		int btnID = btn.getId();

		switch (btnID) {
		case R.id.btn02:
		case R.id.btn04:
		case R.id.btn06:
		case R.id.btn08:
		case R.id.btn11:
		case R.id.btn13:
		case R.id.btn15:
		case R.id.btn17:
		case R.id.btn19:

			return 0;

		case R.id.btn22:
		case R.id.btn24:
		case R.id.btn26:
		case R.id.btn28:
		case R.id.btn31:
		case R.id.btn33:
		case R.id.btn35:
		case R.id.btn37:
		case R.id.btn39:

			return 1;

		case R.id.btn42:
		case R.id.btn44:
		case R.id.btn46:
		case R.id.btn48:
		case R.id.btn51:
		case R.id.btn53:
		case R.id.btn55:
		case R.id.btn57:
		case R.id.btn59:

			return 2;

		case R.id.btn62:
		case R.id.btn64:
		case R.id.btn66:
		case R.id.btn68:
		case R.id.btn71:
		case R.id.btn73:
		case R.id.btn75:
		case R.id.btn77:
		case R.id.btn79:

			return 3;

		case R.id.btn82:
		case R.id.btn84:
		case R.id.btn86:
		case R.id.btn88:

			return 4;

		}
		return -1;
	}

	/**
	 * method to get the column of the clicked line
	 * */
	public int setCol(Button btn) {
		int btnID = btn.getId();

		switch (btnID) {
		case R.id.btn02:
		case R.id.btn11:
		case R.id.btn22:
		case R.id.btn31:
		case R.id.btn42:
		case R.id.btn51:
		case R.id.btn62:
		case R.id.btn71:
		case R.id.btn82:

			return 0;

		case R.id.btn04:
		case R.id.btn13:
		case R.id.btn24:
		case R.id.btn33:
		case R.id.btn44:
		case R.id.btn53:
		case R.id.btn64:
		case R.id.btn73:
		case R.id.btn84:

			return 1;

		case R.id.btn06:
		case R.id.btn15:
		case R.id.btn26:
		case R.id.btn35:
		case R.id.btn46:
		case R.id.btn55:
		case R.id.btn66:
		case R.id.btn75:
		case R.id.btn86:

			return 2;

		case R.id.btn08:
		case R.id.btn17:
		case R.id.btn28:
		case R.id.btn37:
		case R.id.btn48:
		case R.id.btn57:
		case R.id.btn68:
		case R.id.btn77:
		case R.id.btn88:

			return 3;

		case R.id.btn19:
		case R.id.btn39:
		case R.id.btn59:
		case R.id.btn79:

			return 4;
		}
		return -1;
	}

	/**
	 * method to check if game is over
	 * */
	private boolean isOver() {

		if (mGameHandler.getEmptyCellsCount() == 0)
			return true;
		return false;

	}

	/**
	 * method to show fragment when game is over in order to ask for new game or
	 * go back to the Main Menu
	 * */
	private void restartGame() {
		DialogFragment newFragment = new StartGame.EndGameDialog();
		newFragment.show(getFragmentManager(), "missiles");
	}

	/**
	 * method to clean the board
	 * */
	private void cleanBoard() {
		mGameHandler = new GameHandler(BOARD_SIZE);
		lineButtons();

		mPlayerOne.increaseScore(-mPlayerOne.getCurrentScore());
		mPlayerTwo.increaseScore(-mPlayerTwo.getCurrentScore());

		mFirstPlayerTextView.setText(mPlayerOne.getName() + ": 0");
		mSecondPlayerTextView.setText(mPlayerTwo.getName() + ": 0");
		mFirstPlayerTextView.setTextColor(Color.CYAN);
		mSecondPlayerTextView.setTextColor(Color.WHITE);

		// reset signs
		for (int i = 0; i < Constants.signButtons.length; i++) {
			((ImageView) findViewById(Constants.signButtons[i]))
					.setImageDrawable(null);
		}

		// reset lines
		for (int i = 0; i < Constants.gameButtons.length; i++) {
			((Button) findViewById(Constants.gameButtons[i]))
					.setBackgroundColor(Color.TRANSPARENT);
			((Button) findViewById(Constants.gameButtons[i]))
					.setClickable(true);
		}
	}

	/**
	 * method to get the sign view for closed square
	 * */
	public ImageView getImageViewToWritePLayerSign(int row, int col) {
		return (ImageView) findViewById(mSignsIDs.get(row * 10 + col + 1));
	}

	/**
	 * method to fill mLineButtontsNotDrownYet list with the line buttons that
	 * are not clicked yet
	 * */
	private void lineButtons() {
		for (int i = 0; i < Constants.gameButtons.length; i++) {
			mLineButtontsNotDrownYet.add(Constants.gameButtons[i]);
		}

	}

	@SuppressLint("ValidFragment")
	private class EndGameDialog extends DialogFragment {

		@Override
		public Dialog onCreateDialog(Bundle savedInstanceState) {
			// Use the Builder class for convenient dialog construction
			AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
			builder.setMessage(
					String.format(Constants.WINNER_STRING, getWinnerName(),
							getWinnerScore()))
					.setPositiveButton(Constants.CONTINUEUE,
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int id) {
									cleanBoard();
								}
							})
					.setNegativeButton(Constants.MAIN_MANU,
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int id) {
									Intent intent = new Intent(StartGame.this,
											MainActivity.class);
									startActivity(intent);
								}
							});

			if (!getWinnerName().equals(Constants.COMPUTER_PLAYER)) {
				saveHighscore();
			}
			// Create the AlertDialog object and return it
			return builder.create();
		}

		/**
		 * method to save winner's score in the highscore file
		 * */
		private void saveHighscore() {
			StringBuilder sb = new StringBuilder();
			String fileName = Constants.HIGHSCORE_FILE_NAME;
			FileInputStream inputStream;
			List<ResultItem> results = new ArrayList<ResultItem>();
			results.add(new ResultItem(getWinnerName(), getWinnerScore()));
			String newline = System.getProperty(Constants.SEPARATOR);
			try {
				inputStream = openFileInput(fileName);
				InputStreamReader isr = new InputStreamReader(inputStream);
				BufferedReader bufferedReader = new BufferedReader(isr);
				String line;
				while ((line = bufferedReader.readLine()) != null
						&& !line.equals("")) {
					String[] temp = line.split(",");
					results.add(new ResultItem(temp[0], Integer
							.parseInt(temp[1])));
				}
				inputStream.close();
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
			} catch (IOException e) {
				// TODO Auto-generated catch block
			}

			Collections.sort(results, new ScoreComparator());

			FileOutputStream outputStream;
			try {
				outputStream = openFileOutput(fileName, Context.MODE_PRIVATE);
				int i = 0;
				String toWrite = null;
				for (ResultItem res : results) {
					toWrite = res.getName() + "," + res.getScore() + newline;
					outputStream.write(toWrite.getBytes());
					i++;
					if (i == 20) {
						break;
					}
				}

				outputStream.close();
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/**
	 * method to initialize mSignsIDs list with the id's of the image views for
	 * the players signs
	 * */
	private void initSignsIDs() {
		mSignsIDs.put(12, R.id.sign12);
		mSignsIDs.put(14, R.id.sign14);
		mSignsIDs.put(16, R.id.sign16);
		mSignsIDs.put(18, R.id.sign18);
		mSignsIDs.put(32, R.id.sign32);
		mSignsIDs.put(34, R.id.sign34);
		mSignsIDs.put(36, R.id.sign36);
		mSignsIDs.put(38, R.id.sign38);
		mSignsIDs.put(52, R.id.sign52);
		mSignsIDs.put(54, R.id.sign54);
		mSignsIDs.put(56, R.id.sign56);
		mSignsIDs.put(58, R.id.sign58);
		mSignsIDs.put(72, R.id.sign72);
		mSignsIDs.put(74, R.id.sign74);
		mSignsIDs.put(76, R.id.sign76);
		mSignsIDs.put(78, R.id.sign78);
	}

	@Override
	protected void onResume() {
		super.onResume();
		mIsMute = Utils.getIsMute(this);
		Utils.setBackgroundImage(this, findViewById(R.id.activity_game));
		if (MainActivity.mServ != null && mIsMute
				&& !MainActivity.mServ.isPlaying()) {
			MainActivity.mServ.resume();
		}
	}

	@Override
	protected void onPause() {
		super.onPause();
		mIsMute = Utils.getIsMute(this);
		if (MainActivity.mServ != null && mIsMute) {
			MainActivity.mServ.pause();
		}
	}

}
